/*
    实现table类中声明函数的实现
*/
#include "table.h"

table::table() {
    // 从文件中读取数据表
    tFd = open(TABLE_FILE, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
    if (tFd == -1)
        throw "In table::table(),open error";

    // 读取文件中已有的记录数量
    records = new Record[MAX_RECORD_NUM];
    // 判断表格是否为空
    if (lseek(tFd, 0, SEEK_END) == 0) {
        recordNum = 0;
        InitializeTable();
    } else {
        recordNum = lseek(tFd, 0, SEEK_END) / RECORD_SIZE_BYTE;
        lseek(tFd, 0, SEEK_SET);
        read(tFd, records, recordNum * RECORD_SIZE_BYTE);
    }
    tree = new BPTree;
    srand((unsigned) time(NULL)); // 随机数种子

    // 初始化mutex
    pMutexForOperatingTable = new pthread_mutex_t;
    // 互斥量初始化异常处理
    if (pthread_mutex_init(pMutexForOperatingTable, 0) != 0 ) {
        delete pMutexForOperatingTable;
        close(tFd);
        throw "In table::table(),pthread_mutex_init error";
    }
}

// 析构函数
table::~table() {
    if (tFd) {
        close(tFd);
    }
    delete[] records;
}

// 生成随机数填写10000条数据到表中以供测试
void table::InitializeTable() {
    Record record;
    for (int index = 0; index < 10000; index++) {
        record = CreateRecord();
        if (!AppendRecord(record))
            throw "In table::table(),init error";
    }
}


pthread_mutex_t* table::pMutexForCreatingTable = table::InitializeMutex(); // 创建表实例的互斥量
table* table::threadTable = 0;

// 初始化创建表格的互斥量
pthread_mutex_t *table::InitializeMutex() {
    pthread_mutex_t *p = new pthread_mutex_t;
    if (pthread_mutex_init(p, 0) != 0) {
        delete p;
        return 0;
    }
    return p;
}

// 获取table实例
table *table::GetTable() {
    // 只允许同时存在一个表实例，以保证互斥访问
    if (threadTable != 0) {
        return threadTable;
    }
    if (pthread_mutex_lock(pMutexForCreatingTable) != 0) {
        return 0;
    }
    if (threadTable == 0) {
        try {
            threadTable = new table;
        } catch (const char *) {
            pthread_mutex_unlock(pMutexForCreatingTable);
            return 0;
        }
    }
    if (pthread_mutex_unlock(pMutexForCreatingTable) != 0) {
        return 0;
    }
    return threadTable;
}

// 创建一条随机记录并保存到记录数组中
Record table::CreateRecord() {
    Record record;
    recordNum++;
    record.primaryKey = recordNum;
    for (int index = 0; index < RECORD_LENGTH; index++)
        record.recordList[index] = rand() % 2000; // 属性是随机数，设置范围[0,1000]
    records[recordNum - 1] = record;
    return record;
}

// 保存一条记录
bool table::AppendRecord(const Record & record) {
    if (write(tFd, &record, RECORD_SIZE_BYTE) == -1)
        return false;
    return true;
}


// 为第col列的属性创建B+树
BPTreeNode* table::CreateBPTree(int col) {
    BPTreeNode* root = tree->CreateBPTree();
    for (int index = 0; index < recordNum; index++)
        root = tree->InsertNode(root, records[index], col);
    return root;
}

// 更新索引文件
void table::UpdateIndexFile(int col) {
    BPTreeNode* root = CreateBPTree(col);
    tree->SaveBPTree(root, col);
}

// 创建索引文件
void table::CreateIndexFile(BPTreeNode * root, int col) {
    tree->SaveBPTree(root, col);
}

// 判断索引文件是否存在
bool table::IsIndexExists(int col) {
    char IndexFile[20];
    sprintf(IndexFile, "%s%d", INDEX_PREFIX, col);
    if (access(IndexFile, F_OK) == 0)
        return true;
    return false;
}


// 插入记录
void table::InsertRecord() {
    // 对操作表操作加锁
    if (pthread_mutex_lock(pMutexForOperatingTable) != 0)
        throw "In table::InsertRecord(),lock error";
    Record record = CreateRecord();
    // DisplayRecord(records[recordNum-1]);
    if (!AppendRecord(record))
        throw "In table::InsertRecord(),insert error";
    printf("添加成功，插入记录为：\n");
    printf("id\tAttr1\tAttr2\tAttr3\tAttr4\tAttr5\tAttr6\tAttr7\tAttr8\t···\tAttr100\n");
    printf("\t================================================================================\n");
    printf("%ld\t", record.primaryKey);
    DisplayRecord(record);
    printf("目前共有记录%ld条\n", this->recordNum);
    // 更新索引
    for (int col = 1; col < RECORD_LENGTH + 1; col++) {
        if (IsIndexExists(col))
            UpdateIndexFile(col);
    }
    // 释放操作表的锁
    pthread_mutex_unlock(pMutexForOperatingTable);
}

// 搜索记录
void table::SearchRecord(int lowerBound, int upperBounnd, int col) {
    printf("正在搜索第列%d，范围：[%d, %d]\n", col, lowerBound, upperBounnd);
    // 对操作表操作加锁
    pthread_mutex_lock(pMutexForOperatingTable);

    // 存放搜索结果
    int64_t *result = new int64_t[MAX_RESULT_NUM];
    int num = 0;
    BPTreeNode *root; // 存放B+树
    // 首先判断是否有索引文件
    if (IsIndexExists(col)) {
        printf("已查找到索引文件，正在读取...\n");
        root = tree->LoadBPTree(col);
        if (!root) {
            printf("读取索引文件失败\n");
            return ;
        }
    } 
    // 不存在索引则创建一个对应col的索引
    else {
        printf("未查找到索引文件，正在创建...\n");
        root = CreateBPTree(col);
        if (!root) {
            printf("创建索引文件失败\n");
            return;
        }
        // 创建索引文件
        CreateIndexFile(root, col);
        printf("已为第%d列创建索引文件\n", col);
    }

    // 根据区间的上下界选择进入的子流程
    if (lowerBound == upperBounnd) {
        tree->Search4EqualInterval(root, lowerBound, result, num);
    }
    else {
        tree->Search4Interval(root, lowerBound, upperBounnd, result, num);
    }
    printf("搜索结果(前10条)：\n");
    printf("id\tAttr1\tAttr2\tAttr3\tAttr4\tAttr5\tAttr6\tAttr7\tAttr8\t···\tAttr100\n");
    for (int index = 0; index < num; index++){
        printf("\t================================================================================\n");
        printf("%ld\t", records[result[index] - 1].primaryKey);
        DisplayRecord(records[result[index] - 1]);
    }
    // 释放操作表的锁
    pthread_mutex_unlock(pMutexForOperatingTable);
}

// 显示记录
void table::DisplayRecord(const Record & record) {
    for (int index = 0; index < 8; index++) { // 显示前8个属性
        printf("%-5ld\t", record.recordList[index]);
    }
    printf("···\t"); // 中间的属性略掉
    printf("%-5ld\n", record.recordList[-1]); // 显示最后一个属性
}























